package com.immortal.core.module.sigar;

import com.google.common.collect.Lists;
import org.hyperic.sigar.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>系统信息收集和报表工具
 * <pre>
 *     使用例子:   get(OSInfo.builder()
 *                          .filePath("info.txt")// outfile ,default console
 *                          .libPath("D:\\projects\\gitee\\sigarlib") // set the directory about dll or so of sigar
 *                          .osInfo("cpu") //  include some system infos ,default all
 *                          .build());
 * </pre>
 *
 * @author wind
 * @version 1.0
 * @since 2018/12/12
 */
public class OSUtils {
    public static OSUtils os = new OSUtils();

    public static void get(OSInfo osInfo) {
        try {
            List<OSInfoEnum> osInfos;
            if (osInfo.getOsInfo() != null && osInfo.getOsInfo().length > 0) {
                final List<OSInfoEnum> osInfoEnums = Lists.newArrayList();
                List<String> infos = Stream.of(osInfo.getOsInfo()).map(String::toUpperCase).collect(Collectors.toList());
                Stream.of(OSInfoEnum.values()).forEach(v -> {
                    if (infos.contains(v.name())) {
                        osInfoEnums.add(v);
                    }
                });
                osInfos = osInfoEnums;
            } else {
                osInfos = Arrays.asList(OSInfoEnum.values());
            }
            os.print(os.getFile(osInfo), osInfo.getLibPath(), osInfos);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private File getFile(OSInfo osInfo) throws IOException {
        if (osInfo.getFilePath() != null && osInfo.getFilePath().trim().length() > 0) {
            Path path = Paths.get(osInfo.getFilePath());
            if (Files.notExists(path)) {
                Files.createFile(path);
            }
            return path.toFile();
        } else {
            return osInfo.getFile();
        }
    }

    private void print(File file, String[] libPath, List<OSInfoEnum> osInfoEnumList) throws IOException {
        PrintStream printStream = null;
        PrintStream sysOut = System.out;
        try {
            if (file != null) {
                printStream = new PrintStream(new FileOutputStream(file));
                System.setOut(printStream);
            }
            System.out.println("<<<<<<<<Starting");
            System.out.println("<<<<<<<<设置sigar lib 路径");
            addLibrary(libPath);
            osInfoEnumList.forEach(v -> {
                switch (v) {
                    case PROPERTY:
                        System.out.println("-------------System信息，从jvm获取-------------------------");
                        try {
                            property();
                        } catch (UnknownHostException e) {
                            e.printStackTrace();
                        }
                        break;
                    case CPU:
                        System.out.println("-------------cpu信息--------------------------------------");
                        try {
                            cpu();
                        } catch (SigarException e) {
                            e.printStackTrace();
                        }
                        break;
                    case MEMORY:
                        System.out.println("--------------内存信息-------------------------------------");
                        try {
                            memory();
                        } catch (SigarException e) {
                            e.printStackTrace();
                        }
                        break;
                    case OS:
                        System.out.println("--------------操作系统信息---------------------------------");
                        os();
                        break;
                    case WHO:
                        System.out.println("--------------用户信息-------------------------------------");
                        try {
                            who();
                        } catch (SigarException e) {
                            e.printStackTrace();
                        }
                        break;
                    case FILE:
                        System.out.println("--------------文件系统信息----------------------------------");
                        try {
                            file();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    case NET:
                        System.out.println("--------------网络信息--------------------------------------");
                        try {
                            net();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    case ETHERNET:
                        System.out.println("---------------以太网信息-----------------------------------");
                        try {
                            ethernet();
                        } catch (SigarException e) {
                            e.printStackTrace();
                        }
                        break;
                    default:
                }
            });
        } finally {
            System.setOut(sysOut);
            if (printStream != null) {
                printStream.close();
            }
            System.out.println(">>>>>>>打印结束");
        }
    }

    private void addLibrary(String[] libPath) {
        if (libPath == null) {
            return;
        }
        String libs = System.getProperty("java.library.path");
        for (String s : libPath) {
            libs += File.pathSeparator + s;
        }
        System.setProperty("java.library.path", libs);
    }

    private void property() throws UnknownHostException {
        Runtime r = Runtime.getRuntime();
        Properties props = System.getProperties();
        InetAddress addr;
        addr = InetAddress.getLocalHost();
        String ip = addr.getHostAddress();
        Map<String, String> map = System.getenv();
        String userName = map.get("USERNAME");
        String computerName = map.get("COMPUTERNAME");
        String userDomain = map.get("USERDOMAIN");
        System.out.println("用户名:    " + userName);
        System.out.println("计算机名:    " + computerName);
        System.out.println("计算机域名:    " + userDomain);
        System.out.println("本地ip地址:    " + ip);
        System.out.println("本地主机名:    " + addr.getHostName());
        System.out.println("JVM可以使用的总内存:    " + r.totalMemory());
        System.out.println("JVM可以使用的剩余内存:    " + r.freeMemory());
        System.out.println("JVM可以使用的处理器个数:    " + r.availableProcessors());
        System.out.println("Java的运行环境版本：    " + props.getProperty("java.version"));
        System.out.println("Java的运行环境供应商：    " + props.getProperty("java.vendor"));
        System.out.println("Java供应商的URL：    " + props.getProperty("java.vendor.url"));
        System.out.println("Java的安装路径：    " + props.getProperty("java.home"));
        System.out.println("Java的虚拟机规范版本：    " + props.getProperty("java.vm.specification.version"));
        System.out.println("Java的虚拟机规范供应商：    " + props.getProperty("java.vm.specification.vendor"));
        System.out.println("Java的虚拟机规范名称：    " + props.getProperty("java.vm.specification.name"));
        System.out.println("Java的虚拟机实现版本：    " + props.getProperty("java.vm.version"));
        System.out.println("Java的虚拟机实现供应商：    " + props.getProperty("java.vm.vendor"));
        System.out.println("Java的虚拟机实现名称：    " + props.getProperty("java.vm.name"));
        System.out.println("Java运行时环境规范版本：    " + props.getProperty("java.specification.version"));
        System.out.println("Java运行时环境规范供应商：    " + props.getProperty("java.specification.vender"));
        System.out.println("Java运行时环境规范名称：    " + props.getProperty("java.specification.name"));
        System.out.println("Java的类格式版本号：    " + props.getProperty("java.class.version"));
        System.out.println("Java的类路径：    " + props.getProperty("java.class.path"));
        System.out.println("加载库时搜索的路径列表：    " + props.getProperty("java.library.path"));
        System.out.println("默认的临时文件路径：    " + props.getProperty("java.io.tmpdir"));
        System.out.println("一个或多个扩展目录的路径：    " + props.getProperty("java.ext.dirs"));
        System.out.println("操作系统的名称：    " + props.getProperty("os.name"));
        System.out.println("操作系统的构架：    " + props.getProperty("os.arch"));
        System.out.println("操作系统的版本：    " + props.getProperty("os.version"));
        System.out.println("文件分隔符：    " + props.getProperty("file.separator"));
        System.out.println("路径分隔符：    " + props.getProperty("path.separator"));
        System.out.println("行分隔符：    " + props.getProperty("line.separator"));
        System.out.println("用户的账户名称：    " + props.getProperty("user.name"));
        System.out.println("用户的主目录：    " + props.getProperty("user.home"));
        System.out.println("用户的当前工作目录：    " + props.getProperty("user.dir"));
    }

    private void memory() throws SigarException {
        Sigar sigar = new Sigar();
        Mem mem = sigar.getMem();
        // 内存总量
        System.out.println("内存总量:    " + mem.getTotal() / 1024L + "K av");
        // 当前内存使用量
        System.out.println("当前内存使用量:    " + mem.getUsed() / 1024L + "K used");
        // 当前内存剩余量
        System.out.println("当前内存剩余量:    " + mem.getFree() / 1024L + "K free");
        Swap swap = sigar.getSwap();
        // 交换区总量
        System.out.println("交换区总量:    " + swap.getTotal() / 1024L + "K av");
        // 当前交换区使用量
        System.out.println("当前交换区使用量:    " + swap.getUsed() / 1024L + "K used");
        // 当前交换区剩余量
        System.out.println("当前交换区剩余量:    " + swap.getFree() / 1024L + "K free");
    }

    private void cpu() throws SigarException {
        Sigar sigar = new Sigar();
        CpuInfo[] cpuInfoList = sigar.getCpuInfoList();
        CpuPerc[] cpuList = sigar.getCpuPercList();
        // 不管是单块CPU还是多CPU都适用
        for (int i = 0; i < cpuInfoList.length; i++) {
            CpuInfo info = cpuInfoList[i];
            System.out.println("第" + (i + 1) + "块CPU信息");
            // CPU的总量MHz
            System.out.println("CPU的总量MHz:    " + info.getMhz());
            // 获得CPU的卖主，如：Intel
            System.out.println("CPU生产商:    " + info.getVendor());
            // 获得CPU的类别，如：Celeron
            System.out.println("CPU类别:    " + info.getModel());
            // 缓冲存储器数量
            System.out.println("CPU缓存数量:    " + info.getCacheSize());
            printCpuPerc(cpuList[i]);
        }
    }

    private void printCpuPerc(CpuPerc cpu) {
        // 用户使用率
        System.out.println("CPU用户使用率:    " + CpuPerc.format(cpu.getUser()));
        // 系统使用率
        System.out.println("CPU系统使用率:    " + CpuPerc.format(cpu.getSys()));
        // 当前等待率
        System.out.println("CPU当前等待率:    " + CpuPerc.format(cpu.getWait()));
        System.out.println("CPU当前错误率:    " + CpuPerc.format(cpu.getNice()));
        // 当前空闲率
        System.out.println("CPU当前空闲率:    " + CpuPerc.format(cpu.getIdle()));
        // 总的使用率
        System.out.println("CPU总的使用率:    " + CpuPerc.format(cpu.getCombined()));
    }

    private void os() {
        OperatingSystem OS = OperatingSystem.getInstance();
        // 操作系统内核类型如： 386、486、586等x86
        System.out.println("操作系统:    " + OS.getArch());
        System.out.println("操作系统CpuEndian():    " + OS.getCpuEndian());
        System.out.println("操作系统DataModel():    " + OS.getDataModel());
        // 系统描述
        System.out.println("操作系统的描述:    " + OS.getDescription());
        // 操作系统类型
        System.out.println("OS.getName():    " + OS.getName());
        System.out.println("OS.getPatchLevel():    " + OS.getPatchLevel());
        // 操作系统的卖主
        System.out.println("操作系统的卖主:    " + OS.getVendor());
        // 卖主名称
        System.out.println("操作系统的卖主名:    " + OS.getVendorCodeName());
        // 操作系统名称
        System.out.println("操作系统名称:    " + OS.getVendorName());
        // 操作系统卖主类型
        System.out.println("操作系统卖主类型:    " + OS.getVendorVersion());
        // 操作系统的版本号
        System.out.println("操作系统的版本号:    " + OS.getVersion());
    }

    private void who() throws SigarException {
        Sigar sigar = new Sigar();
        Who who[] = sigar.getWhoList();
        if (who != null && who.length > 0) {
            for (int i = 0; i < who.length; i++) {
                System.out.println("当前系统进程表中的用户名" + i);
                Who _who = who[i];
                System.out.println("用户控制台:    " + _who.getDevice());
                System.out.println("用户host:    " + _who.getHost());
                System.out.println("getTime():    " + _who.getTime());
                // 当前系统进程表中的用户名
                System.out.println("当前系统进程表中的用户名:    " + _who.getUser());
            }
        }
    }

    private void file() throws Exception {
        Sigar sigar = new Sigar();
        FileSystem[] fileSystemList = sigar.getFileSystemList();
        try {
            for (int i = 0; i < fileSystemList.length; i++) {
                System.out.println("分区的盘符名称" + i);
                FileSystem fs = fileSystemList[i];
                // 分区的盘符名称
                System.out.println("盘符名称:    " + fs.getDevName());
                // 分区的盘符名称
                System.out.println("盘符路径:    " + fs.getDirName());
                System.out.println("盘符标志:    " + fs.getFlags());
                // 文件系统类型，比如 FAT32、NTFS
                System.out.println("盘符类型:    " + fs.getSysTypeName());
                // 文件系统类型名，比如本地硬盘、光驱、网络文件系统等
                System.out.println("盘符类型名:    " + fs.getTypeName());
                // 文件系统类型
                System.out.println("盘符文件系统类型:    " + fs.getType());
                FileSystemUsage usage = null;
                try {
                    usage = sigar.getFileSystemUsage(fs.getDirName());
                } catch (SigarException e) {
                }
                if (usage == null) {
                    continue;
                }
                switch (fs.getType()) {
                    // TYPE_UNKNOWN ：未知
                    case 0:
                        break;
                    // TYPE_NONE
                    case 1:
                        break;
                    // TYPE_LOCAL_DISK : 本地硬盘
                    case 2:
                        // 文件系统总大小
                        System.out.println(fs.getDevName() + "总大小:    " + usage.getTotal() + "KB");
                        // 文件系统剩余大小
                        System.out.println(fs.getDevName() + "剩余大小:    " + usage.getFree() + "KB");
                        // 文件系统可用大小
                        System.out.println(fs.getDevName() + "可用大小:    " + usage.getAvail() + "KB");
                        // 文件系统已经使用量
                        System.out.println(fs.getDevName() + "已经使用量:    " + usage.getUsed() + "KB");
                        double usePercent = usage.getUsePercent() * 100D;
                        // 文件系统资源的利用率
                        System.out.println(fs.getDevName() + "资源的利用率:    " + usePercent + "%");
                        break;
                    // TYPE_NETWORK ：网络
                    case 3:
                        break;
                    // TYPE_RAM_DISK ：闪存
                    case 4:
                        break;
                    // TYPE_CDROM ：光驱
                    case 5:
                        break;
                    // TYPE_SWAP ：页面交换
                    case 6:
                        break;
                    default:
                }
                System.out.println(fs.getDevName() + "读出：    " + usage.getDiskReads());
                System.out.println(fs.getDevName() + "写入：    " + usage.getDiskWrites());
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }

        return;
    }

    private void net() throws Exception {
        Sigar sigar = new Sigar();
        String[] netInterfaceList = sigar.getNetInterfaceList();
        for (int i = 0; i < netInterfaceList.length; i++) {
            String name = netInterfaceList[i];
            NetInterfaceConfig netInterfaceConfig = sigar.getNetInterfaceConfig(name);
            // 网络设备名
            System.out.println("网络设备名:    " + name);
            // IP地址
            System.out.println("IP地址:    " + netInterfaceConfig.getAddress());
            // 子网掩码
            System.out.println("子网掩码:    " + netInterfaceConfig.getNetmask());
            if ((netInterfaceConfig.getFlags() & 1L) <= 0L) {
                System.out.println("!IFF_UP...skipping getNetInterfaceStat");
                continue;
            }
            NetInterfaceStat netInterfaceStat = sigar.getNetInterfaceStat(name);
            // 接收的总包裹数
            System.out.println(name + "接收的总包裹数:" + netInterfaceStat.getRxPackets());
            // 发送的总包裹数
            System.out.println(name + "发送的总包裹数:" + netInterfaceStat.getTxPackets());
            // 接收到的总字节数
            System.out.println(name + "接收到的总字节数:" + netInterfaceStat.getRxBytes());
            // 发送的总字节数
            System.out.println(name + "发送的总字节数:" + netInterfaceStat.getTxBytes());
            // 接收到的错误包数
            System.out.println(name + "接收到的错误包数:" + netInterfaceStat.getRxErrors());
            // 发送数据包时的错误数
            System.out.println(name + "发送数据包时的错误数:" + netInterfaceStat.getTxErrors());
            // 接收时丢弃的包数
            System.out.println(name + "接收时丢弃的包数:" + netInterfaceStat.getRxDropped());
            // 发送时丢弃的包数
            System.out.println(name + "发送时丢弃的包数:" + netInterfaceStat.getTxDropped());
        }
    }

    private void ethernet() throws SigarException {
        Sigar sigar = new Sigar();
        String[] netInterfaces = new String[0];
        try {
            netInterfaces = sigar.getNetInterfaceList();
        } catch (SigarException e) {
            System.out.println("ethernet() sigar.getNetInterfaceList error");
        }
        for (int i = 0; i < netInterfaces.length; i++) {
            NetInterfaceConfig cfg = sigar.getNetInterfaceConfig(netInterfaces[i]);
            if (NetFlags.LOOPBACK_ADDRESS.equals(cfg.getAddress()) || (cfg.getFlags() & NetFlags.IFF_LOOPBACK) != 0
                    || NetFlags.NULL_HWADDR.equals(cfg.getHwaddr())) {
                continue;
            }
            // IP地址
            System.out.println(cfg.getName() + "IP地址:" + cfg.getAddress());
            // 网关广播地址
            System.out.println(cfg.getName() + "网关广播地址:" + cfg.getBroadcast());
            // 网卡MAC地址
            System.out.println(cfg.getName() + "网卡MAC地址:" + cfg.getHwaddr());
            // 子网掩码
            System.out.println(cfg.getName() + "子网掩码:" + cfg.getNetmask());
            // 网卡描述信息
            System.out.println(cfg.getName() + "网卡描述信息:" + cfg.getDescription());
            System.out.println(cfg.getName() + "网卡类型" + cfg.getType());

        }
    }
}
